package main;


import Lib3d.Draw;
import Lib3d.EventListeners.MyKeyListener;
import Lib3d.EventListeners.MyMouseListener;
import Lib3d.MyUtils.Camera;
import Lib3d.MyUtils.Debug;
import Lib3d.MyUtils.MaterialLibSingleton;
import Lib3d.SceneGraph.Impl.AnimatedGroupImpl;
import Lib3d.Scenes.Scene;
import Lib3d.Scenes.SceneFactory;

import com.sun.opengl.util.j2d.TextRenderer;

import java.awt.Font;
import java.nio.FloatBuffer;
import java.text.DecimalFormat;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;

public class JavaRenderer implements GLEventListener {

    public static final GLU glu = new GLU();
    private static GL gl;
    private final AnimatedGroupImpl sceneGraphRoot = new AnimatedGroupImpl();

    private TextRenderer textRenderer, altRenderer;
    private int frameCount = 0;
    private long startTime;
    private String fpsText = "00";
    private final DecimalFormat format = new DecimalFormat("####.00");
    private int fpsWidth;

    public void display(final GLAutoDrawable gLDrawable) {
        // display callback
        JavaRenderer.gl = gLDrawable.getGL();
        // clear color and depth buffer
        JavaRenderer.gl.glClear(GL.GL_COLOR_BUFFER_BIT);
        JavaRenderer.gl.glClear(GL.GL_DEPTH_BUFFER_BIT);

        // Transformations (equivalent a une translation de 300cm de la cam�ra
        // suivant l'axe Z et une translation de 100cm suivant l'axe Y)
        JavaRenderer.gl.glLoadIdentity();
        JavaRenderer.gl.glTranslatef(Camera.getTranslatedX(), Camera.getTranslatedY(),
                Camera.getTranslatedZ());
        JavaRenderer.gl.glRotatef(Camera.getRotatedX(), 1.0f, 0.0f, 0.0f);
        JavaRenderer.gl.glRotatef(Camera.getRotatedY(), 0.0f, 1.0f, 0.0f);
        JavaRenderer.gl.glRotatef(Camera.getRotatedZ(), 0.0f, 0.0f, 1.0f);

        // Affichage du rep�re du monde
        if (Debug.showAxis) {
            Draw.drawAxis(gLDrawable, 400.0f);
        }

        // Affichage du graphe de scene
        this.sceneGraphRoot.draw(gLDrawable);

        // prise en compte de l'animation
        // this.sceneGraphRoot.run();

        if (Debug.showHelp) {
            this.displayFPSText(gLDrawable);
            this.displayDemoText(gLDrawable);
        }

    }

    public void displayChanged(final GLAutoDrawable gLDrawable,
            final boolean modeChanged, final boolean deviceChanged) {}

    public void init(final GLAutoDrawable gLDrawable) {
        JavaRenderer.gl = gLDrawable.getGL();

        // --------------------------
        // Initialisation de la scene
        // --------------------------

        this.initScene();
        this.initTextRenderer();

        // -----------------------
        // Initialisations OpenGL
        // -----------------------

        // init callback
        JavaRenderer.gl.glShadeModel(GL.GL_SMOOTH); // Mode de shading

        // Couleur utilis�e pour l'effacement du color buffer init z-buffer
        JavaRenderer.gl.glClearColor(255f, 255f, 255f, 255f);
        JavaRenderer.gl.glClearDepth(1.0f);
        JavaRenderer.gl.glEnable(GL.GL_DEPTH_TEST);
        JavaRenderer.gl.glDepthFunc(GL.GL_LEQUAL);
        JavaRenderer.gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
        // Autorise l'utilisation des textures
        JavaRenderer.gl.glEnable(GL.GL_TEXTURE_2D);
        // Autorise l'utilisation des lumi�res
        JavaRenderer.gl.glEnable(GL.GL_LIGHTING);
        // Active la lumi�re 0
        JavaRenderer.gl.glEnable(GL.GL_LIGHT0);
        final float[] lightColor = {
                0.4f, 0.4f, 0.4f
        }; // Couleur de la
           // lumi�re
        final float[] lightPosition = {
                0.0f, 0.0f, 0.0f
        }; // Position de la
           // lumi�re
           // Initialisation des composantes colorim�triques de la lumi�re
        JavaRenderer.gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT,
                FloatBuffer.wrap(lightColor));
        JavaRenderer.gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE,
                FloatBuffer.wrap(lightColor));
        JavaRenderer.gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR,
                FloatBuffer.wrap(lightColor));
        // Positionnement de la lumi�re dans l'environnement
        JavaRenderer.gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION,
                FloatBuffer.wrap(lightPosition));

        // listener clavier
        gLDrawable.addKeyListener(new MyKeyListener());
        gLDrawable.addMouseMotionListener(new MyMouseListener());

    }

    public void reshape(final GLAutoDrawable gLDrawable, final int x, final int y,
            final int width, int height) {
        final GL gl = gLDrawable.getGL();
        if (height <= 0) {
            height = 1;
        }
        // camera and perspective
        final float h = (float) width / (float) height;
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        JavaRenderer.glu.gluPerspective(50.0f, h, 1.0f, 1000.0f);
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

    private void displayDemoText(final GLAutoDrawable drawable) {
        TextRenderer renderer;

        if (this.altRenderer == null) {
            final Font font = new Font("Arial", Font.TRUETYPE_FONT, 15);
            this.altRenderer = new TextRenderer(font, true, false);
            this.altRenderer.setSmoothing(true);
        }
        renderer = this.altRenderer;

        // Calculate text location and color
        final String[] str = Debug.getHelpMessage();
        // Calculate text location and color
        renderer.beginRendering(drawable.getWidth(), drawable.getHeight());
        final float c = 0f;
        renderer.setColor(c, c, c, 255);
        final int x = 10;
        final int y = drawable.getHeight() - (str.length * 18);
        String text = "";
        for (int i = 0; i < str.length; i++) {

            text = str[i];
            // int textWidth = (int) textRenderer.getBounds(text).getWidth();
            renderer.draw(text, x, y + (i * 20));

        }
        renderer.endRendering();
    }

    private void displayFPSText(final GLAutoDrawable drawable) {
        if (++this.frameCount == 100) {
            final long endTime = System.currentTimeMillis();
            final float fps = 100.0f / (endTime - this.startTime) * 1000;
            this.frameCount = 0;
            this.startTime = System.currentTimeMillis();

            this.fpsText = "FPS: " + this.format.format(fps);
            if (this.fpsWidth == 0) {
                // Place it at a fixed offset wrt the upper right corner
                this.fpsWidth = (int) this.textRenderer.getBounds("FPS: 10000.00")
                        .getWidth();
            }
        }

        if (this.fpsWidth == 0) {
            return;
        }

        // Calculate text location and color
        final int x = drawable.getWidth() - this.fpsWidth - 5;
        final int y = drawable.getHeight() - 30;
        final float c = 0f;

        // Render the text
        this.textRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
        this.textRenderer.setColor(c, c, c, 255);
        this.textRenderer.draw(this.fpsText, x, y);
        this.textRenderer.endRendering();
    }

    private void initScene() {

        // AnimatedGroupImpl gr1 = new AnimatedGroupImpl();
        final Scene sc1 = SceneFactory.createScene(Scene.HAIRY_SPHERE_2);
        // gr1.addChild(sc1.draw());
        // gr1.addAnimation(AnimationFactory.createSimpleAnimation());
        this.sceneGraphRoot.addChild(sc1.draw());
        // this.sceneGraphRoot.addAnimation(AnimationFactory.createSimpleAnimation());

        // Charge et enregistre les materiaux
        MaterialLibSingleton.getInstance().registerTextures(JavaRenderer.gl);

    }

    private void initTextRenderer() {
        // Create the text renderer
        final Font font = new Font("SansSerif", Font.BOLD, 24);
        this.textRenderer = new TextRenderer(font, true, false);
    }

}